package main

import (
	"fmt"
	"math"
	"sort"
	"time"
)

// 1. 实现对圆形、三角形、长方形求面积。
// 2. 利用第1题，构造3个以上图形，
// 至少圆形、三角形、矩形各有一个，对上题的图形按照面积降序排列
type Areaer interface {
	Area() float64
}

// 父类
type Graph struct {
	AreaRes float64
}

func (g *Graph) Area() float64 {
	return 0
}

// 子
// 圆形
type Circle struct {
	Graph
	R float64
}

func NewCircle(r float64) *Circle {
	return &Circle{R: r}
}

func (c *Circle) Area() float64 {
	if c.AreaRes == 0 {
		c.AreaRes = math.Pi * c.R * c.R
	}
	return c.AreaRes
}

func (c *Circle) String() string {
	return fmt.Sprintf("[circle]r:%v area:%v\n", c.R, c.AreaRes)
}

// 三角形
type Triangle struct {
	Graph
	Bottom float64
	Height float64
}

func NewTriangle(bottom, height float64) *Triangle {
	return &Triangle{Bottom: bottom, Height: height}
}

func (t *Triangle) Area() float64 {
	if t.AreaRes == 0 {
		t.AreaRes = t.Bottom * t.Height / 2
	}
	return t.AreaRes
}

func (t *Triangle) String() string {
	return fmt.Sprintf("[triangle]bottom:%v height:%v area:%v\n", t.Bottom, t.Height, t.AreaRes)
}

// 矩形
type Rectangle struct {
	Graph
	Width  float64
	Height float64
}

func NewRectangle(width, height float64) *Rectangle {
	return &Rectangle{Width: width, Height: height}
}

func (r *Rectangle) Area() float64 {
	if r.AreaRes == 0 {
		r.AreaRes = r.Width * r.Height
	}
	return r.AreaRes
}

func (r *Rectangle) String() string {
	return fmt.Sprintf("[rectangle]width:%v height:%v area:%v\n", r.Width, r.Height, r.AreaRes)
}

// 计算面积
func CalcArea(graph Areaer) float64 {
	return graph.Area()
}

// 实现排序
type AreaSlice []Areaer

func (a AreaSlice) Len() int           { return len(a) }
func (a AreaSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a AreaSlice) Less(i, j int) bool { return a[i].Area() < a[j].Area() }

// 计算面积测试并排序
func testCalcArea() {
	c := NewCircle(1)
	fmt.Println("圆形面积:", CalcArea(c))
	t := NewTriangle(1, 2)
	fmt.Println("三角形面积:", CalcArea(t))
	r := NewRectangle(1, 2)
	fmt.Println("矩形面积:", CalcArea(r))
	as := AreaSlice{c, t, r}
	sort.Sort(sort.Reverse(as))
	fmt.Println(as)
}

// 3、分析斐波那契数列递推公式递归版本的问题，试着为该函数提供一个Cache，使其计算效率提升
var fiboCache = make(map[int]int)

func fiboMap2(n int) int {
	if res, ok := fiboCache[n]; ok {
		return res
	}
	if n == 1 || n == 2 {
		fiboCache[n] = 1
		return 1
	}
	res := fiboMap2(n-1) + fiboMap2(n-2)
	fiboCache[n] = res
	return res
}

// 4、8年前的今天上午9点30分要求：
// 1. 毫秒时间戳是多少？
// 2. 格式化输出时间为 2005/09/10 21:35:40 +0800 的形式3. 请问那天是周几？
// 到那天，本年已经过了多少周？
// 4. 距离今天已经过了多少天了？

type weekDayCN time.Weekday

var longDayNamesCN = []string{
	"星期天",
	"星期一",
	"星期二",
	"星期三",
	"星期四",
	"星期五",
	"星期六",
}

func (d weekDayCN) String() string {
	if time.Sunday <= time.Weekday(d) && time.Weekday(d) <= time.Saturday {
		return longDayNamesCN[d]
	}
	buf := make([]byte, 20)
	n := fmtInt(buf, uint64(d))
	return "%!Weekday(" + string(buf[n:]) + ")"
}

func fmtInt(buf []byte, v uint64) int {
	w := len(buf)
	if v == 0 {
		w--
		buf[w] = '0'
	} else {
		for v > 0 {
			w--
			buf[w] = byte(v%10) + '0'
			v /= 10
		}
	}
	return w
}

func CalcTime()  {
	now := time.Now()
	t1 := time.Date(now.Year() - 8, now.Month(), now.Day(), 9, 30, now.Second(), now.Nanosecond(), now.Location())
	fmt.Println("毫秒时间戳：", t1.UnixMilli())
	fmt.Println("格式化：", t1.Format("2006/01/02 15:04:05 -0700"))
	fmt.Println("周几：", weekDayCN(t1.Weekday()))
	d:= now.Sub(t1)
	d1 := math.Floor(d.Hours() / 24)
	w := math.Floor(d.Hours()/ 24 / 7)
	fmt.Println("已过多少周：", w)
	fmt.Println("距离今天已过多少天：", d1)
}
